import Lex
import Draw
import Stms


#传入tokens
def testCode(tokens):
  #程序入口寻找
  if not(len(tokens)>5 and tokens[0][1]=="main" and tokens[1][1]=="(" and tokens[2][1]==")"):
      raise Exception("error:[pre] 无法在开头找到程序入口!")
  #获取一个语法单元
  retDict1=Stms.getCodeUnit(tokens)
  #碰到的第一个语法单元必须是Block 
  if retDict1["status"]==2:
    if len(retDict1["new"]) ==0:  #最外层block后不能有其他token
      retDict2=Stms.testBlock(retDict1["need"],0,[])
      if not retDict2["status"]:
        raise Exception("error:未知异常发生!")
      needTree={"root":["ProgStart",[[3,"main"],[1,"("],[1,")"]]],"leafA":retDict2["needTree"]}
      return retDict2["asmCodes"],retDict2["table"],needTree
    else:
      raise Exception("error:[pre] 在}后,在"+retDict1["new"][0][1]+"之前发现错误,在根语法块之后的非法字符")
  else:
    raise Exception("error:[pre] 直到文本尾部,未能找到合适的语法块")


def getCode():
  code=""
  tid=input("请选择您的输入方式(0键盘输入|others文件输入):")
  if tid=='0':
    code=input("请输入待检测代码:")
  else:
    fileName=input("请输入代码文件名:")
    with open(fileName,'r') as f:
      code=f.readlines()
  return code

def getAddress(id,table):
  for idinfo in table:
    if id==idinfo["id"]:
      return idinfo["addr"]
  return -1

def getAsmCodes(asmCodes,table,fileName):
  JumpOp=["jae","jbe","je","jne","ja","jb","jmp"]
  JumpFormat=["j>=","j<=","j=","j!=","j>","j<","j"]
  calOp=["add","sub","mul","div"]
  calFormat=["+","-","*","/"]
  content=""
  for line in asmCodes:
    op=line["op"] 
    if line["op"] in JumpFormat:
      op=JumpOp[JumpFormat.index(line["op"])]
    elif line["op"] in calFormat:
      op=calOp[calFormat.index(line["op"])]
    elif line["op"]==":=":
      op="store"
      
    arg1=""
    if not (str(line["arg1"]).isspace() or len(str(line["arg1"]))==0):
      if str(line["arg1"])[0]=="t":
        arg1="r"+line["arg1"][1:]
      elif getAddress(line["arg1"],table)!=-1:
        arg1="addr["+str(getAddress(line["arg1"],table))+"]"
      else:
        arg1=line["arg1"]
    arg2=""
    if not (str(line["arg2"]).isspace() or len(str(line["arg2"]))==0):
      if str(line["arg2"])[0]=="t":
        arg2="r"+line["arg2"][1:]
      elif getAddress(line["arg2"],table)!=-1:
        arg2="addr["+str(getAddress(line["arg2"],table))+"]"
      else:
        arg2=line["arg2"]
    if op[0]!="j":
      content=content+str(op)+"   "+str(arg1)+" , "+str(arg2)+"\n"
    else:
      content=content+str(op)+"   "+str(arg1)+"\n"
  with open(fileName,"w") as f :
    f.write(content)
  
if __name__ == "__main__":
  try:
      #1.获取待检测代码
    code=getCode()
    #2.送入词法分析器 得到词汇token
    tokens=Lex.process(code)
    print("[词法分析结果]:"+str(tokens))
    print("[词数]:"+str(len(tokens)))
    #3.进行代码分析
    [asmCodes,table,treeDict]=testCode(tokens)  
    print("生成的中间代码四元式是:")
    print("row\t op\t arg1\t arg2\t res")
    for line in asmCodes:
      for v in line.values():
        print(v, end="\t")
      print("\n")
    
    print("符号表:")
    print("id\t type\t size\t addr\t")
    for line in table:
      for v in line.values():
        print(v, end="\t")
      print("\n")
    print("伪汇编代码生成在 伪汇编.s文件中")
    getAsmCodes(asmCodes,table,"伪汇编.s")
    # print(treeDict)
    print("绘图中..")
    Draw.drawTree(treeDict)
    print("绘图完成")
    print("生成的中间代码四元式是:")
    print("row\t op\t arg1\t arg2\t res")
    for line in asmCodes:
      for v in line.values():
        print(v, end="\t")
      print("\n")
  except Exception as e:
    print(e) 

 
